package com.czy.workflow.core.executor;

import com.czy.workflow.core.context.FlowContext;
import com.czy.workflow.core.exception.FlowException;
import com.czy.workflow.core.exception.FlowNodeOperationInvalidException;
import com.czy.workflow.core.model.FlowBranch;
import com.czy.workflow.core.model.FlowNode;
import com.czy.workflow.core.model.TaskInfo;
import com.czy.workflow.core.validator.FlowValidator;

import java.util.List;
import java.util.logging.Logger;

public abstract class AbstractTaskExecutor implements TaskExecutor {

    Logger logger = Logger.getLogger(AbstractTaskExecutor.class.getName());

    FlowContext flowContext;

    ThreadLocal<TaskInfo> threadLocal = new ThreadLocal<>();

    TaskInfo taskInfoInit;


    /**
     * 调用自定义（注解）任务
     * @param taskInfo
     * @return 自定义方法的结果，如果没有则默认为true
     */
    public abstract boolean invokeExecutorComponent(TaskInfo taskInfo);


    /**
     * 执行配置流程任务
     * @param taskInfo
     * @return
     * @throws FlowException
     */
    public abstract boolean executeTask(TaskInfo taskInfo) throws FlowException;

    /**
     * 调用节点配置任务
     * @param taskInfo
     * @return
     * @throws FlowException
     */
    public abstract boolean invokeNodeComponent(TaskInfo taskInfo) throws FlowException;


    /**
     * 校验当前节点
     * @param taskInfo
     * @return
     * @throws FlowException
     */
    public boolean validate(TaskInfo taskInfo) throws FlowException {
        for(FlowValidator validator : flowContext.getValidatorList()){
            if(!validator.validate(flowContext, taskInfo)){
                return false;
            }
        }
        return true;
    }




    /**
     * @param taskInfo
     * @return
     * @throws FlowException
     */
    @Override
    public boolean execute(TaskInfo taskInfo) throws FlowException{
        logger.info(String.format("------ current flow & node -> [%s, %s] ------", taskInfo.getFlowCode(), taskInfo.getNode().getCode()));

        //校验节点
        if(!this.validate(taskInfo)){
            throw new FlowNodeOperationInvalidException(taskInfo);
        }

        flowContext.getTaskListenerNotify().before(taskInfo, true);

        boolean result = true;

        //调用注解任务
        result = this.invokeExecutorComponent(taskInfo);

        //调用节点配置任务
        if(result){
            result = this.invokeNodeComponent(taskInfo);
        }

        //最后进行流程流转
        if(result){
            result = this.executeTask(taskInfo);
        }

        flowContext.getTaskListenerNotify().after(taskInfo, result);

        flowContext.getFlowService().saveFlowLog(taskInfo, result);

        return result;
    }

    @Override
    public boolean execute(String docId, String nodeId, String option) throws FlowException {
        TaskInfo taskInfo = flowContext.getFlowService().getTaskInfoByDocId(docId, nodeId);
        if(taskInfo == null){
            return false;
        }
        taskInfo.setOption(option);
        taskInfo.setFlowOrgElement(flowContext.getFlowService().getCurrentUser());
        return execute(taskInfo);
    }


    @Override
    public void run() {
        //使用线程模式执行
        try {
            threadLocal.set(this.taskInfoInit);
            this.execute(this.taskInfoInit);
        } catch (FlowException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void setFlowContext(FlowContext flowContext) {
        this.flowContext = flowContext;
    }




    public void setTaskInfo(TaskInfo taskInfo){
        this.taskInfoInit = taskInfo;
    }

    public TaskInfo getTaskInfo(){
        return threadLocal.get() != null ? threadLocal.get() : this.taskInfoInit;
    }
}
